原始题目:剑指 Offer 65. 不用加减乘除做加法 (opens new window)

解题思路:

本题考察的是通过位运算来做加法。

加法需要考虑进位,在位运算里,进位可以通过左移然后加回无进位和中。

假设有两个数的二进制形式 aabb。其和 s=a+bs = a + b。对于第 ii 位来说,a(ia(i) 和 b(i)b(i) 相加可能有以下的结果。

a(i)a(i) b(i)b(i) 无进位和 n(i)n(i) 进位 c(i+1)c(i+1)
00 00 00 00
11 00 11 00
00 11 11 00
11 11 00 11

观察可以看出,n(i)n(i)a(i)a(i)b(i)b(i) 异或的结果,而 c(i+1)c(i+1)a(i)a(i)b(i)b(i) 与运算然后左移一位的结果。

{n=abc=(a&b)<<1\begin{cases} n = a ⊕ b \\ c = (a \& b ) << 1 \end{cases}

因此,求 ss 的过程转化成求 aabb 的无进位和 nn 以及进位 cc 的过程,然后将 cc 补还给 nn。补还之后,可能会产生新的进位,因此需要循环处理,直到进位为 00

s=a+bn+cs = a + b → n + c

这个过程同样适合与 aa 或者 bb 为负数的时候,因为正数负数都是用补码存储的。

代码:

public int add(int a, int b) {
    while (b != 0) {
        // 求进位
        int c = (a & b) << 1;
        // 不考虑进位,结果赋值给 a
        a = a ^ b;
        // 如果存在进位,则 b != 0,那么在下一个循环中,
        // 就会将进位和 a 相加,直到进位为 0
        b = c;
    }
    return a;
}
1
2
3
4
5
6
7
8
9
10
11
12

复杂度分析

  • 时间复杂度O(1)O(1):最差情况下(例如 aa = 0x7fffffff​ , b=1b = 1 时),需循环 3232 次,使用 O(1)O(1) 时间;每轮中的常数次位操作使用 O(1)O(1) 时间。
  • 空间复杂度O(1)O(1):辅助变量占用常数大小的空间。
上次更新: 2023/10/15